package com;
import java.util.*;

public class FolderItem {
    public int size = 0; //文件元素大小
    public boolean ishidden = false; //是否隐藏
    public boolean directory; //是否为文件夹
    public String name = null; //文件元素名称
    public FolderItem fatherItems = null; //父文件元素
    private Vector<FolderItem> folderItems; //文件夹下子文件元素

    public FolderItem(int size, boolean ishidden, boolean directory, String name, FolderItem fatherItems) {
        this.size = size;
        this.ishidden = ishidden;
        this.directory = directory;
        this.name = name;
        this.fatherItems = fatherItems;
        folderItems = new Vector<FolderItem>();
    }

    /**
     * 返回当前文件元素的绝对路径
     */
    public String getFullPath() {
        if (fatherItems == null) return "";
        return fatherItems.getFullPath() + "/" + name; //向上递归遍历
    }

    /**
     * 判断文件名是否合法
     * @param name 文件名
     * @return 是否合法（合法为 true）
     */
    private boolean isValidFileName(String name) {
        return name.matches("^[^+-./\\t\b@#$%*()\\[\\]][^/\\t\b@#$%*()\\[\\]]{1,254}$");
    }

    /**
     * 在当前目录文件下，根据路径查询并返回目标目录元素
     * @param path 输入路径
     * @return 目标目录元素
     * path 应当是文件系统中存在的目录，否则输出 path not found (已在其他函数中实现)
     */
    public FolderItem findFolderItem(Vector<String> path) {
        if (path.size() == 0) return this;
        if (path.firstElement().equals("..")) { //跳转到父目录
            if (fatherItems != null) {
                path.remove(0);
                return fatherItems.findFolderItem(path);
            } else { //如果没有父目录，非法路径
                System.out.println("path not found");
                return null;
            }
        }
        while (true) {
            if (path.firstElement().equals(".")  || path.firstElement().equals("")) {
                path.remove(0);
            } else {
                break;
            }
        }
        for (FolderItem subitem: folderItems) {
            if (subitem.name.equals(path.firstElement())) {
                path.remove(0);
                return subitem.findFolderItem(path); //递归到下一个目录查询
            }
        }
        System.out.println("path not found"); //没有找到
        return null;
    }


    /**
     * 修改文件
     * 在正常情况下，同名文件(如果有的话)应当先被删除，然后新建文件。
     * 如果存在同名的目录，输出 a dretory with the same name exists
     * name 应该是合法的文件名，否则输出 bad usage
     * @param name 文件名称
     * @param size 文件大小
     * @param ishidden 是否隐藏
     */
    public void touch(String name, int size, boolean ishidden) {
        if (!isValidFileName(name)) {
            System.out.println("bad usage");
            return;
        }
        /*判断同名文件元素*/
        for (FolderItem file:
                folderItems) {
            if (file.name.equals(name)) {
                if (file.directory) { //存在同名的目录
                    System.out.println("a dretory with the same name exists");
                    return;
                } else { //存在同名的文件
                    folderItems.remove(file);
                    break;
                }
            }
        }
        folderItems.add(new FolderItem(size, ishidden, false, name, this)); //新建文件
    }

    /**
     * 创建目录
     * name 应该是合法的文件名，否则输出 bad usage
     * 如果存在一个同名目录或文件，输出 file or directory with the same name exists (已在其他函数中实现)
     * @param name 目录名称
     * @param ishidden 是否隐藏
     */
    public void mkdir(String name, boolean ishidden) {
        if (!isValidFileName(name)) { //判断文件名是否合法
            System.out.println("bad usage");
            return;
        }

        for (FolderItem file: folderItems) { //判断同名文件项目
            if (file.name.equals(name)) {
                System.out.println("file or dretory with the same name exists");
                return;
            }
        }
        folderItems.add(new FolderItem(0, ishidden, true, name, this)); //新建目录

    }

    /**
     * 列出当前目录下所有文件和文件夹
     * 如果没有一个需要输出的内容，输出 [empty] (已在其他函数中实现)
     * 对于列举的每个文件，输出单独的一行，依次为文件绝对路径、文件大小，以及 hidden （如果有隐藏属性）、 dir （如果是目录）。
     * @param recursive 递归列举（列举子目录)
     * @param show_hidden 输出隐藏文件
     * @param show_dir 只输出目录
     * @param show_file 只输出文件
     * @param path 根路径
     * @return 是否输出内容
     */
    public boolean ls(boolean recursive, boolean show_hidden, boolean show_dir, boolean show_file, String path) {
        boolean flag = false; //是否输出内容
        for (FolderItem file:
             folderItems) {
            if ((!file.ishidden || show_hidden) && ((file.directory && !show_file) || (!file.directory && !show_dir))) {
                System.out.printf("%s %d", path + file.name, file.size);
                if (file.ishidden) System.out.print(" hidden");
                if (file.directory) System.out.print(" dir");
                System.out.println("");
                flag = true;
            }
            /*递归枚举输出*/
            if (recursive) {
                if (file.ls(recursive, show_hidden, show_dir, show_file, path + file.name + "/"))
                    flag = true;
            }
        }
        return flag;
    }
    /**
     * 删除当前目录下的目标元素
     */
    protected void rm(FolderItem target) {
        folderItems.remove(target);
    }

    /**
     * 删除当前目录元素
     * 如果是文件夹则递归删除子目录下文件
     * 如果当前目录为根目录，输出 cannot remove root
     */
    public void rm() {
        if (fatherItems == null) {
            System.out.println("cannot remove root");
            return;
        }
        fatherItems.rm(this);
    }


    public boolean isEmpty() {
        return folderItems.isEmpty();
    }

}
